import java.io.IOException;

public class Analyzer extends Thread {

	private Logger log;
	private PacketBuffer pb;

	public Analyzer(PacketBuffer pb, String logFile)
	{
		this.log = new Logger(logFile);
		this.pb = pb;
		this.start();
	}

	public synchronized void run()
	{
		byte b;

		while (!isInterrupted()) {
			try {
				b = pb.readByte();
				analyze(b);
			} catch (ParsePacketException e) {
				System.out.println(e.getMessage());
				e.printStackTrace();
				this.interrupt();
			}
		}
	}

	private void printPacketToLog(Packet packet)
	{
		packet.printToLog(log);
	}

	private void analyze(byte b) throws ParsePacketException
	{
		switch (b)
		{
		//Keep Alive
		case (byte) 0x00:
			//log.write("Keep Alive");
			printPacketToLog(parsePacket00(b));
		break;
		// Login request
		case (byte) 0x01:
			//log.write("Login request");
			printPacketToLog(parsePacket01(b));
		break;
		case (byte) 0x02:
			//log.write("Handshake");
			printPacketToLog(parsePacket02(b));
		break;
		case (byte) 0x03:
			printPacketToLog(parsePacket03(b));break;
		case (byte) 0x04:
			printPacketToLog(parsePacket04(b));break;
		case (byte) 0x05:
			printPacketToLog(parsePacket05(b));break;
		case (byte) 0x06:
			printPacketToLog(parsePacket06(b));break;
		case (byte) 0x07:
			printPacketToLog(parsePacket07(b));break;
		case (byte) 0x08:
			printPacketToLog(parsePacket08(b));break;
		case (byte) 0x09:
			printPacketToLog(parsePacket09(b));break;
		case (byte) 0x0A:
			printPacketToLog(parsePacket0A(b));break;
		case (byte) 0x0B:
			printPacketToLog(parsePacket0B(b));break;
		case (byte) 0x0C:
			printPacketToLog(parsePacket0C(b));break;
		case (byte) 0x0D:
			printPacketToLog(parsePacket0D(b));break;
		case (byte) 0x0E:
			printPacketToLog(parsePacket0E(b));break;
		case (byte) 0x0F:
			printPacketToLog(parsePacket0F(b));break;
		case (byte) 0x10:
			printPacketToLog(parsePacket10(b));break;
		case (byte) 0x11:
			printPacketToLog(parsePacket11(b));break;
		case (byte) 0x12:
			printPacketToLog(parsePacket12(b));break;
		case (byte) 0x13:
			printPacketToLog(parsePacket13(b));break;
		case (byte) 0x14:
			printPacketToLog(parsePacket14(b));break;
		case (byte) 0x15:
			printPacketToLog(parsePacket15(b));break;
		case (byte) 0x16:
			printPacketToLog(parsePacket16(b));break;
		case (byte) 0x17:
			printPacketToLog(parsePacket17(b));break;
		case (byte) 0x18:
			printPacketToLog(parsePacket18(b));break;
		case (byte) 0x19:
			printPacketToLog(parsePacket19(b));break;
		case (byte) 0x1A:
			printPacketToLog(parsePacket1A(b));break;
		case (byte) 0x1C:
			printPacketToLog(parsePacket1C(b));break;
		case (byte) 0x1D:
			printPacketToLog(parsePacket1D(b));break;
		case (byte) 0x1E:
			printPacketToLog(parsePacket1E(b));break;
		case (byte) 0x1F:
			printPacketToLog(parsePacket1F(b));break;
		case (byte) 0x20:
			printPacketToLog(parsePacket20(b));break;
		case (byte) 0x21:
			printPacketToLog(parsePacket21(b));break;
		case (byte) 0x22:
			printPacketToLog(parsePacket22(b));break;
		case (byte) 0x23:
			printPacketToLog(parsePacket23(b));break;
		case (byte) 0x26:
			printPacketToLog(parsePacket26(b));break;
		case (byte) 0x27:
			printPacketToLog(parsePacket27(b));break;
		case (byte) 0x28:
			printPacketToLog(parsePacket28(b));break;
		case (byte) 0x29:
			printPacketToLog(parsePacket29(b));break;
		case (byte) 0x2A:
			printPacketToLog(parsePacket2A(b));break;
		case (byte) 0x2B:
			printPacketToLog(parsePacket2B(b));break;
		case (byte) 0x32:
			printPacketToLog(parsePacket32(b));break;
		case (byte) 0x33:
			printPacketToLog(parsePacket33(b));break;
		case (byte) 0x34:
			printPacketToLog(parsePacket34(b));break;
		case (byte) 0x35:
			printPacketToLog(parsePacket35(b));break;
		case (byte) 0x36:
			printPacketToLog(parsePacket36(b));break;
		case (byte) 0x3C:
			printPacketToLog(parsePacket3C(b));break;
		case (byte) 0x3D:
			printPacketToLog(parsePacket3D(b));break;
		case (byte) 0x46:
			printPacketToLog(parsePacket46(b));break;
		case (byte) 0x47:
			printPacketToLog(parsePacket47(b));break;
		case (byte) 0x64:
			printPacketToLog(parsePacket64(b));break;
		case (byte) 0x65:
			printPacketToLog(parsePacket65(b));break;
		case (byte) 0x66:
			printPacketToLog(parsePacket66(b));break;
		case (byte) 0x67:
			printPacketToLog(parsePacket67(b));break;
		case (byte) 0x68:
			printPacketToLog(parsePacket68(b));break;
		case (byte) 0x69:
			printPacketToLog(parsePacket69(b));break;
		case (byte) 0x6A:
			printPacketToLog(parsePacket6A(b));break;
		case (byte) 0x6B:
			printPacketToLog(parsePacket6B(b));break;
		case (byte) 0x6C:
			printPacketToLog(parsePacket6C(b));break;
		case (byte) 0x82:
			printPacketToLog(parsePacket82(b));break;
		case (byte) 0x83:
			printPacketToLog(parsePacket83(b));break;
		case (byte) 0x84:
			printPacketToLog(parsePacket84(b));break;
		case (byte) 0xC8:
			printPacketToLog(parsePacketC8(b));break;
		case (byte) 0xC9:
			printPacketToLog(parsePacketC9(b));break;
		case (byte) 0xCA:
			printPacketToLog(parsePacketCA(b));break;
		case (byte) 0xFA:
			printPacketToLog(parsePacketFA(b));break;
		case (byte) 0xFE:
			printPacketToLog(parsePacketFE(b));
		break;
		case (byte) 0xFF:
			printPacketToLog(parsePacketFF(b));
		break;
		default:
			log.write("Unknow packet : "+String.format("%x", b));
			break;
		}
	}

	/*
	 * Disconnect/kick packet
	 */
	public Packet parsePacketFF(byte b) throws ParsePacketException
	{
		Packet p = new Packet(b);
		p.addField(new Field("Reason", "String", pb.readString()));
		return p;
	}

	/*
	 * Server List Ping packet
	 */
	public Packet parsePacketFE(byte b) throws ParsePacketException
	{
		Packet p = new Packet(b);
		return p;
	}

	/*
	 * Plugin Message
	 */
	private Packet parsePacketFA(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		byte[] data;
		int length;

		p.addField(new Field("Channel", "string", pb.readString()));
		length = pb.readShort();
		p.addField(new Field("length", "short", length));
		data = new byte[length];
		pb.readByte(data, 0, length);
		p.addField(new Field("data", "byte array", data));
		return p;
	}

	/*
	 * Play Abilities
	 */
	private Packet parsePacketCA(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Invulnerability?", "boolean", pb.readBool()));
		p.addField(new Field("Is flying?", "boolean", pb.readBool()));
		p.addField(new Field("Can fly?", "boolean", pb.readBool()));
		p.addField(new Field("Instant Destroy?", "boolean", pb.readBool()));
		return p;
	}

	/*
	 * Player List Item
	 */
	private Packet parsePacketC9(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Player name", "string", pb.readString()));
		p.addField(new Field("Online", "boolean", pb.readBool()));
		p.addField(new Field("Ping", "short", pb.readShort()));
		return p;
	}

	/*
	 * Increment Statistic
	 */
	private Packet parsePacketC8(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Statistic ID", "int", pb.readInt()));
		p.addField(new Field("Amount", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Update Tile Entity
	 */
	private Packet parsePacket84(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "short", pb.readShort()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Action", "byte", pb.readByte()));
		p.addField(new Field("Custom 1", "int", pb.readInt()));
		p.addField(new Field("Custom 2", "int", pb.readInt()));
		p.addField(new Field("Custom 3", "int", pb.readInt()));

		return p;
	}

	/*
	 * Item Data
	 */
	private Packet parsePacket83(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		byte[] text;
		int length;
		p.addField(new Field("Item Type", "short", pb.readShort()));
		p.addField(new Field("Item ID", "short", pb.readShort()));
		length =  pb.readByte();
		p.addField(new Field("Text length", "byte", length));
		text = new byte[length];
		for (int i = 0;i < length;i++)
			text[i] = pb.readByte();
		p.addField(new Field("Window ID", "byte", new String(text)));
		return p;
	}

	/*
	 * Update Sign
	 */
	private Packet parsePacket82(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "short", pb.readShort()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Text1", "string", pb.readString()));
		p.addField(new Field("Text2", "string", pb.readString()));
		p.addField(new Field("Text3", "string", pb.readString()));
		p.addField(new Field("Text4", "string", pb.readString()));
		return p;
	}

	/*
	 * Enchant Item
	 */
	private Packet parsePacket6C(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Window ID", "byte", pb.readByte()));
		p.addField(new Field("Enchantment", "byte", pb.readByte()));
		return p;
	}


	/*
	 * Creative Inventory Action
	 */
	private Packet parsePacket6B(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Slot", "short", pb.readShort()));
		p.addField(new Field("Clicked item", "slot", pb.readSlot()));
		return p;
	}

	/*
	 * Confirm Transaction
	 */
	private Packet parsePacket6A(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Window ID", "byte", pb.readByte()));
		p.addField(new Field("Action number", "short", pb.readShort()));
		p.addField(new Field("Accepted ?", "boolean", pb.readBool()));
		return p;
	}

	/*
	 * Update Window Property
	 */
	private Packet parsePacket69(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Window ID", "byte", pb.readByte()));
		p.addField(new Field("Property", "short", pb.readShort()));
		p.addField(new Field("Value", "short", pb.readShort()));
		return p;
	}

	/*
	 * Set Window Items
	 */
	private Packet parsePacket68(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		int nbSlot;
		String slots = "";
		p.addField(new Field("Window ID", "byte", pb.readByte()));
		nbSlot = pb.readShort();
		p.addField(new Field("Count", "short", nbSlot));
		for (int i = 0;i < nbSlot; i++)
			slots = slots + "[" + pb.readSlot() + "]";
		p.addField(new Field("Slot data", "array of slots", slots));
		return p;
	}

	/*
	 * Set Slot
	 */
	private Packet parsePacket67(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Window ID", "byte", pb.readByte()));
		p.addField(new Field("Slot", "short", pb.readShort()));
		p.addField(new Field("Slot Data", "slot", pb.readSlot()));
		return p;
	}

	/*
	 * Click Window
	 */
	private Packet parsePacket66(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Window ID", "byte", pb.readByte()));
		p.addField(new Field("Slot", "short", pb.readShort()));
		p.addField(new Field("Right-click", "byte", pb.readByte()));
		p.addField(new Field("Action number", "short", pb.readShort()));
		p.addField(new Field("Shift?", "boolean", pb.readBool()));
		p.addField(new Field("Clicked item", "slot", pb.readSlot()));
		return p;
	}

	/*
	 * Close Window
	 */
	private Packet parsePacket65(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Window ID", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Open Window
	 */
	private Packet parsePacket64(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Window ID", "byte", pb.readByte()));
		p.addField(new Field("Inventory Type", "byte", pb.readByte()));
		p.addField(new Field("Window title", "string", pb.readString()));
		p.addField(new Field("Number of Slots", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Thunderbolt
	 */
	private Packet parsePacket47(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Unknown", "boolean", pb.readBool()));
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "int", pb.readInt()));
		p.addField(new Field("Z", "int", pb.readInt()));
		return p;
	}

	/*
	 * Change Game State
	 */
	private Packet parsePacket46(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Reason", "byte", pb.readByte()));
		p.addField(new Field("Game mode", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Sound/Particle Effect
	 */
	private Packet parsePacket3D(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Effect ID", "int", pb.readInt()));
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "byte", pb.readByte()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Data", "int", pb.readInt()));
		return p;
	}

	/*
	 * Explosion
	 */
	private Packet parsePacket3C(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		int count;
		byte[][] records;
		p.addField(new Field("X", "double", pb.readDouble()));
		p.addField(new Field("Y", "double", pb.readDouble()));
		p.addField(new Field("Z", "double", pb.readDouble()));
		p.addField(new Field("Unknown", "float", pb.readFloat()));
		count = pb.readInt();
		p.addField(new Field("Record count", "int", count));
		records = new byte[count][3];
		for (int i = 0;i < count; i++)
		{
			records[i][0] = pb.readByte();
			records[i][1] = pb.readByte();
			records[i][2] = pb.readByte();
		}
		p.addField(new Field("Records", "byte array", records));
		return p;
	}

	/*
	 * Block Action
	 */
	private Packet parsePacket36(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "short", pb.readShort()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Byte 1", "byte", pb.readByte()));
		p.addField(new Field("Byte 2", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Block Change
	 */
	private Packet parsePacket35(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "byte", pb.readByte()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Block Type", "byte", pb.readByte()));
		p.addField(new Field("Block Metadata", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Multi block Change
	 */
	private Packet parsePacket34(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		int size;
		int[] data;
		
		p.addField(new Field("Chunk X", "int", pb.readInt()));
		p.addField(new Field("Chunk Z", "int", pb.readInt()));
		p.addField(new Field("Record count", "short", pb.readShort()));
		size = pb.readInt();
		p.addField(new Field("Data size", "int", size));
		data = new int[size / 4];
		for (int i = 0;i < size / 4; i++)
			data[i] = pb.readInt();
		p.addField(new Field("Records", "byte array", data));
		return p;
	}

	/*
	 * Map Chunks
	 */
	private Packet parsePacket33(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		int size;
		byte[] chunk;
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "int", pb.readInt()));
		p.addField(new Field("Ground-up continuous", "boolean", pb.readBool()));
		p.addField(new Field("Primary bit map", "short", pb.readShort()));
		p.addField(new Field("Add bit amp", "short", pb.readShort()));
		size = pb.readInt();
		p.addField(new Field("Compressed size", "int", size));
		p.addField(new Field("Unused", "int", pb.readInt()));
		chunk = new byte[size];
		pb.readByte(new byte[size], 0, size);
		p.addField(new Field("Compressed data", "byte array", chunk));
		return p;
	}

	/*
	 * Map Column Allocation
	 */
	private Packet parsePacket32(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "int", pb.readInt()));
		p.addField(new Field("Mode", "boolean", pb.readBool()));
		return p;
	}

	/*
	 * Set Experience
	 */
	private Packet parsePacket2B(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Experience bar", "float", pb.readFloat()));
		p.addField(new Field("ELevel", "short", pb.readShort()));
		p.addField(new Field("Total experience", "short", pb.readShort()));
		return p;
	}

	/*
	 * Remove Entity Effect
	 */
	private Packet parsePacket2A(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Effect ID", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Entity Effect
	 */
	private Packet parsePacket29(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Effect ID", "byte", pb.readByte()));
		p.addField(new Field("Amplifier", "byte", pb.readByte()));
		p.addField(new Field("Duration", "short", pb.readShort()));
		return p;
	}

	/*
	 * Entity Metadata
	 */
	private Packet parsePacket28(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Entity Metadata", "byte", pb.readEMeta()));
		return p;
	}

	/*
	 * Attach Entity
	 */
	private Packet parsePacket27(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Vehicle ID", "int", pb.readInt()));
		return p;
	}

	/*
	 * Entity Status
	 */
	private Packet parsePacket26(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Entity Status", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Entity Head Look
	 */
	private Packet parsePacket23(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Head Yaw", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Entity Teleport
	 */
	private Packet parsePacket22(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "int", pb.readInt()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Yaw", "byte", pb.readByte()));
		p.addField(new Field("Pitch", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Entity Look and Relative Move
	 */
	private Packet parsePacket21(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("dX", "byte", pb.readByte()));
		p.addField(new Field("dY", "byte", pb.readByte()));
		p.addField(new Field("dZ", "byte", pb.readByte()));
		p.addField(new Field("Yaw", "byte", pb.readByte()));
		p.addField(new Field("Pitch", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Entity Look
	 */
	private Packet parsePacket20(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Yaw", "byte", pb.readByte()));
		p.addField(new Field("Pitch", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Entity Relative Move
	 */
	private Packet parsePacket1F(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("dX", "byte", pb.readByte()));
		p.addField(new Field("dY", "byte", pb.readByte()));
		p.addField(new Field("dZ", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Entity
	 */
	private Packet parsePacket1E(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		return p;
	}

	/*
	 * Destroy Entity
	 */
	private Packet parsePacket1D(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		return p;
	}

	/*
	 * Entity Velocity
	 */
	private Packet parsePacket1C(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Velocity X", "short", pb.readShort()));
		p.addField(new Field("Velocity Y", "short", pb.readShort()));
		p.addField(new Field("Velocity Z", "short", pb.readShort()));
		return p;
	}

	/*
	 * Spawn Experience Orb
	 */
	private Packet parsePacket1A(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "int", pb.readInt()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Count", "short", pb.readShort()));
		return p;
	}

	/*
	 * Spawn Painting
	 */
	private Packet parsePacket19(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Title", "String", pb.readString()));
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "int", pb.readInt()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Direction", "int", pb.readInt()));
		return p;
	}

	/*
	 * Spawn Mob
	 */
	private Packet parsePacket18(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Type", "byte", pb.readByte()));
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "int", pb.readInt()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Yaw", "byte", pb.readByte()));
		p.addField(new Field("Pitch", "byte", pb.readByte()));
		p.addField(new Field("Head Yaw", "byte", pb.readByte()));
		p.addField(new Field("Metadata", "metadata", pb.readEMeta()));
		return p;
	}

	/*
	 * Spawn Object/Vehicle
	 */
	private Packet parsePacket17(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Type", "byte", pb.readByte()));
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "int", pb.readInt()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Fireball thrower's entity ID", "int", pb.readInt()));
		p.addField(new Field("Speed X", "short", pb.readShort()));
		p.addField(new Field("Speed Y", "short", pb.readShort()));
		p.addField(new Field("Speed Z", "short", pb.readShort()));
		return p;
	}

	/*
	 * Collect Item
	 */
	private Packet parsePacket16(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Collected Entity ID", "int", pb.readInt()));
		p.addField(new Field("Collector Entity ID", "int", pb.readInt()));
		return p;
	}

	/*
	 * Spawn Dropped Item
	 */
	private Packet parsePacket15(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Item", "short", pb.readShort()));
		p.addField(new Field("Count", "byte", pb.readByte()));
		p.addField(new Field("Damage/Data", "short", pb.readShort()));
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "int", pb.readInt()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Rotation", "byte", pb.readByte()));
		p.addField(new Field("Pitch", "byte", pb.readByte()));
		p.addField(new Field("Roll", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Spawn Named Entity
	 */
	private Packet parsePacket14(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Player Name", "String", pb.readString()));
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "int", pb.readInt()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Yaw", "byte", pb.readByte()));
		p.addField(new Field("Pitch", "byte", pb.readByte()));
		p.addField(new Field("Current Item", "short", pb.readShort()));
		return p;
	}

	/*
	 * Entity Action
	 */
	private Packet parsePacket13(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Action ID", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Animation
	 */
	private Packet parsePacket12(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Animation", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Use Bed
	 */
	private Packet parsePacket11(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Unkown", "byte", pb.readByte()));
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "byte", pb.readByte()));
		p.addField(new Field("Z", "int", pb.readInt()));
		return p;
	}

	/*
	 * Held Item Change
	 */
	private Packet parsePacket10(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Slot ID", "short", pb.readShort()));
		return p;
	}

	/*
	 * Player Block Placement
	 */
	private Packet parsePacket0F(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "byte", pb.readByte()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Direction", "byte", pb.readByte()));
		p.addField(new Field("Held item", "slot", pb.readSlot()));
		return p;
	}

	/*
	 * Player Digging
	 */
	private Packet parsePacket0E(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Status", "byte", pb.readByte()));
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "byte", pb.readByte()));
		p.addField(new Field("Z", "int", pb.readInt()));
		p.addField(new Field("Face", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Player Position & Look
	 */
	private Packet parsePacket0D(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("X", "double", pb.readDouble()));
		p.addField(new Field("Y", "double", pb.readDouble()));
		p.addField(new Field("Stance", "double", pb.readDouble()));
		p.addField(new Field("Z", "double", pb.readDouble()));
		p.addField(new Field("Yaw", "float", pb.readFloat()));
		p.addField(new Field("Pitch", "float", pb.readFloat()));
		p.addField(new Field("On Ground", "bool", pb.readBool()));
		return p;
	}

	/*
	 * PLayer Look
	 */
	private Packet parsePacket0C(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Yaw", "float", pb.readFloat()));
		p.addField(new Field("Pitch", "float", pb.readFloat()));
		p.addField(new Field("On Ground", "bool", pb.readBool()));
		return p;
	}

	/*
	 * Player Position
	 */
	private Packet parsePacket0B(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("X", "double", pb.readDouble()));
		p.addField(new Field("Y", "double", pb.readDouble()));
		p.addField(new Field("Stance", "double", pb.readDouble()));
		p.addField(new Field("Z", "double", pb.readDouble()));
		p.addField(new Field("On Ground", "bool", pb.readBool()));
		return p;
	}

	/*
	 * Player
	 */
	private Packet parsePacket0A(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("On Ground", "bool", pb.readBool()));
		return p;
	}

	/*
	 * Respawn
	 */
	private Packet parsePacket09(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Dimension", "int", pb.readInt()));
		p.addField(new Field("Difficulty", "byte", pb.readByte()));
		p.addField(new Field("Creative mode", "byte", pb.readByte()));
		p.addField(new Field("World heaight", "short", pb.readShort()));
		p.addField(new Field("Level Type", "String", pb.readString()));
		return p;
	}

	/*
	 * Update Health
	 */
	private Packet parsePacket08(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Health", "short", pb.readShort()));
		p.addField(new Field("Food", "short", pb.readShort()));
		p.addField(new Field("Food Saturation", "float", pb.readFloat()));
		return p;
	}

	/*
	 * Use Entity
	 */
	private Packet parsePacket07(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("User", "int", pb.readInt()));
		p.addField(new Field("Target", "int", pb.readInt()));
		p.addField(new Field("Mouse button", "bool", pb.readBool()));
		return p;
	}

	/*
	 * Spawn Position
	 */
	private Packet parsePacket06(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("X", "int", pb.readInt()));
		p.addField(new Field("Y", "int", pb.readInt()));
		p.addField(new Field("Z", "int", pb.readInt()));
		return p;
	}

	/*
	 * Entity Equipment
	 */
	private Packet parsePacket05(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Entity ID", "int", pb.readInt()));
		p.addField(new Field("Slot", "short", pb.readShort()));
		p.addField(new Field("Item ID", "short", pb.readShort()));
		p.addField(new Field("Damage", "short", pb.readShort()));
		return p;
	}

	/*
	 * Time Update
	 */
	private Packet parsePacket04(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Time", "long", pb.readLong()));
		return p;
	}

	/*
	 * Chat Message
	 */
	private Packet parsePacket03(byte b) throws ParsePacketException {
		Packet p = new Packet(b);
		p.addField(new Field("Message", "String", pb.readString()));
		return p;
	}

	/*
	 * Handshake
	 */
	public Packet parsePacket02(byte b) throws ParsePacketException
	{
		Packet p = new Packet(b);
		p.addField(new Field("Username and Host", "String", pb.readString()));
		return p;
	}



	/*
	 * Login request packet
	 */
	public Packet parsePacket01(byte b) throws ParsePacketException
	{
		int size = 0;
		Packet p = new Packet(b);
		p.addField(new Field("Protocol Version", "int", pb.readInt()));
		p.addField(new Field("Username", "String", pb.readString()));
		p.addField(new Field("Not Used", "String", pb.readString()));
		p.addField(new Field("Not Used", "int", pb.readInt()));
		p.addField(new Field("Not Used", "int", pb.readInt()));
		p.addField(new Field("Not Used", "byte", pb.readByte()));
		p.addField(new Field("Not Used", "byte", pb.readByte()));
		p.addField(new Field("Not Used", "byte", pb.readByte()));
		return p;
	}

	/*
	 * Keep Alive packet
	 */
	public Packet parsePacket00(byte b) throws ParsePacketException
	{
		int size = 0;
		Packet p = new Packet(b);
		p.addField(new Field("Keep-alive ID", "int", pb.readInt()));
		size = size + 4;
		p.setSize(size);
		return p;
	}

}
